<?php
/**
 * Created by PhpStorm.
 * User: inhere
 * Date: 2016/3/18
 * Time: 17:50
 */

namespace app\parsers;

use inhere\librarys\exceptions\NotFoundException;
use Slim;
use slimExt\DataCollector;
use app\extensions\MderItem;
use app\extensions\MderPage;
use cebe\markdown\GithubMarkdown;

/**
 * Class AbstractParser
 * @package app\parsers
 */
abstract class AbstractParser
{
    /**
     * @var MderPage
     */
    protected $pager;

    /**
     * 默认值
     * @var array
     */
    protected $options = [
        'tagStart'  => '{###',
        'tagEnd'    => '###}'
    ];

    /**
     * @var array|mixed
     */
    protected $attrs = [
        'author'      => '',
        'status'      => 1, //allows: public member private draft
        'pageTitle'   => '',
        'description' => '',
        'keywords'    => '',
        'title'       => '',
        'digest'      => '',
        'tags'        => [],
        'publishTime' => '',
        'updateTime' => '',
        'prevPage'    => false,
        'nextPage'    => false,
        'route'       => '',
    ];

    const UNKNOWN = 'UNKNOWN';

    /**
     * cebe\markdown(`composer require cebe/markdown`) -- 多行代码块解析有问题
     *   - \cebe\markdown\Markdown, method: parse()
     *   - \cebe\markdown\GithubMarkdown, method: parse()
     *   - \cebe\markdown\MarkdownExtra, method: parse()
     *
     * HyperDown(composer.json: `require:  "joyqi/hyper-down" : "dev-master",`) -- 效果不错
     *  - \HyperDown\Parser , method: makeHtml()
     *
     * Parsedown(`composer require erusev/parsedown-extra`) -- 效果不错
     *  - \Parsedown , method: text()
     *  - \ParsedownExtra, method: text()
     *
     * classname:method
     *
     * @var string
     */
    protected $markdownParser = '\Parsedown:text';

    public static function make(MderPage $pager = null)
    {
        return new static($pager);
    }

    /**
     * @param MderPage   $pager
     */
    public function __construct(MderPage $pager = null)
    {
        $this->setPager($pager);
    }

    abstract public function parse();


    /**
     * collect Page Sidebar Data
     * @return array|string
     */
    public function collectSidebarData()
    {
        $sidebarData = '';
        $sidebar = Slim::config()->renderSidebar;

        // have sidebar data config or item exists?
        if ( !$sidebar || !$this->getItem()->exists() ) {
            return $sidebarData;
        }

        // render sidebar
        $sidebarFile = null;
// d($this->getItem());
        // render default sidebar config file
        if ( $sidebar === true ) {
            $sidebarFile = $this->getItem()->defaultSidebarFile;
            if ( is_file($sidebarFile) ) {
                $this->getItem()->set('sidebarFile',$sidebarFile);
            }
        } elseif ( is_string($sidebar) ) {
            $sidebarFile = Slim::alias(trim($sidebar));
            $maybeFile = $this->getItem()->path . DIR_SEP . $sidebarFile;

            if ( is_file($sidebarFile) ) {
                $this->getItem()->set('sidebarFile',$sidebarFile);
            }elseif ( is_file($maybeFile) )  {
                $this->getItem()->set('sidebarFile',$maybeFile);
            }
        }

        if ($sidebarFile = $this->getItem()->sidebarFile) {
            $ext = pathinfo($sidebarFile, PATHINFO_EXTENSION);

            if ($ext === 'yml' || $ext === 'yaml') {
                $sidebarData = DataCollector::parseYaml($sidebarFile);
            } elseif ($ext === 'json') {
                $sidebarData = DataCollector::parseJson($sidebarFile);
            } elseif ($ext === 'md') {
                $sidebarData = $this->parseMarkdown(file_get_contents($sidebarFile));
            } elseif ($ext === 'html') {
                $sidebarData = file_get_contents($sidebarFile);
            }
        }

        return $sidebarData;
    }

    /**
     * parse markdown text
     * @param string $text
     * @return string
     */
    protected function parseMarkdown($text)
    {
        list($class, $method) = explode(':', $this->markdownParser);

        if ( !class_exists($class) ) {
            throw new NotFoundException("markdown parser class [$class] not found!");
        }

        // 效果不错
        $parser = new $class;
        $html = $parser->$method($text);

        return trim($html);
    }


    /*********************************************************************************
     * getter/setter
     *********************************************************************************/

    /**
     * @return MderPage
     */
    public function getPager()
    {
        return $this->pager;
    }

    /**
     * @param  MderPage $pager
     * @return MderPage
     */
    public function setPager($pager)
    {
        if ($pager instanceof MderPage) {
            $this->pager = $pager;
        }

        return $this;
    }

    /**
     * @return MderItem
     */
    public function getItem()
    {
        return $this->pager->getItem();
    }

    /**
     * @return array
     */
    public function getOptions()
    {
        return $this->options;
    }

    /**
     * @param array $options
     */
    public function setOptions($options)
    {
        $this->options = $options;
    }

    /**
     * @return array
     */
    public function getAllowSetting()
    {
        return array_keys($this->attrs);
    }

    /**
     * @param $name
     * @return mixed
     */
    public function __get($name)
    {
        $getter = 'get'. ucfirst($name);

        if ( method_exists($this, $getter) ) {
            return $this->$getter();
        }

        throw new \BadMethodCallException("get property $name don't exists!");
    }

    /**
     * @param bool $handle
     * @return array|mixed
     */
    public function getAttrs($handle=false)
    {
        if ($handle) {
            !$this->attrs['pageTitle'] && ($this->attrs['pageTitle'] = $this->attrs['title']);
            !$this->attrs['description'] && ($this->attrs['description'] = $this->attrs['title']);
        }

        return $this->attrs;
    }

    /**
     * @param array|mixed $attrs
     */
    public function setAttrs($attrs)
    {
        $this->attrs = array_merge($this->attrs, $attrs);
    }
}